package chapter14.core;

import java.lang.reflect.*;

import java.util.*;

import com.softwarementors.extjs.djn.config.annotations.*;

import org.apache.commons.fileupload.FileItem;

import org.hibernate.*;

import org.hibernate.criterion.Restrictions;


public abstract class DirectAction<T> extends BaseAction {
    protected Class entityClass;

    public DirectAction() {
        super();

        this.entityClass = GenericsUtils.getSuperClassGenricType(this
                .getClass());
    }

    // ==================================================== save
    @DirectFormPostMethod
    public Object save(Map<String, String> param,
        Map<String, FileItem> files) throws Exception {
        T entity = this.fetchEntity(param);

        if (this.isCreate(param)) {
            this.beforeCreate(entity, param);
        } else {
            this.beforeUpdate(entity, param);
        }

        this.beforeSave(entity, param);

        this.onSave(entity);

        return this.afterSave(entity);
    }

    protected void beforeSave(T entity, Map<String, String> param)
        throws Exception {
        this.copyEntity(param, entity);
    }

    protected void beforeCreate(T entity, Map<String, String> param)
        throws Exception {
    }

    protected void beforeUpdate(T entity, Map<String, String> param)
        throws Exception {
    }

    protected void onSave(T entity) throws Exception {
        this.getEntityDao().save(entity);
    }

    protected Object afterSave(T entity) throws Exception {
        return new Result(entity);
    }

    // ==================================================== list
    @DirectMethod
    public Object list() throws Exception {
        String hql = this.beforeList();

        List<T> list = this.onList(hql);

        return this.afterList(list);
    }

    protected String beforeList() {
        return "from " + this.getEntityClass().getName();
    }

    protected List<T> onList(String hql) {
        return this.getEntityDao().find(hql);
    }

    protected Object afterList(List<T> list) {
        return list;
    }

    // ==================================================== pagedQuery
    @DirectMethod
    public Object pagedQuery(int start, int limit, String sort,
        String dir, String query) throws Exception {
        String hql = this.beforePagedQuery(sort, dir, query);
        int pageNo = (start / limit) + 1;
        int pageSize = limit;
        Page page = this.onPagedQuery(hql, pageNo, pageSize);

        return this.afterPagedQuery(page);
    }

    protected boolean notEmpty(String str) {
        return !this.isEmpty(str);
    }

    protected boolean isEmpty(String str) {
        return (str == null) || str.trim().equals("");
    }

    protected String beforePagedQuery(String sort, String dir, String query) {
        String hql = "from " + this.getEntityClass().getName();

        if (this.notEmpty(query)) {
            hql += (" where name like '%" + query + "%'");
        }

        if (this.notEmpty(sort) && this.notEmpty(dir)) {
            hql += (" order by " + sort + " " + dir);
        }

        return hql;
    }

    protected Page onPagedQuery(String hql, int pageNo, int pageSize) {
        return this.getEntityDao().pagedQuery(hql, pageNo, pageSize);
    }

    protected Object afterPagedQuery(Page page) {
        return page;
    }

    // ==================================================== remove
    @DirectMethod
    public Object remove(String ids) throws Exception {
        for (String str : ids.split(",")) {
            try {
                long id = Long.parseLong(str);
                this.removeById(id);
            } catch (Exception ex) {
                System.err.println(ex);
            }
        }

        return new Result("success");
    }

    protected void removeById(long id) throws Exception {
        this.getEntityDao().removeById(id);
    }

    // ==================================================== utility
    protected abstract HibernateEntityDao<T> getEntityDao();

    protected Class<T> getEntityClass() {
        return this.entityClass;
    }

    protected void copyEntity(Map<String, String> param, Object entity) {
        MainUtils.copyMap(param, entity);
    }

    protected long fetchId(Map<String, String> param) {
        long id = 0L;

        try {
            id = Long.parseLong(param.get("id"));
        } catch (Exception ex) {
        }

        return id;
    }

    protected T fetchEntity(Map<String, String> param)
        throws Exception {
        long id = this.fetchId(param);
        T entity = null;

        if (id == 0L) {
            entity = (T) this.entityClass.newInstance();
        } else {
            entity = (T) this.getEntityDao().get(id);
        }

        return entity;
    }

    protected boolean isUpdate(Map<String, String> param) {
        return this.fetchId(param) != 0L;
    }

    protected boolean isCreate(Map<String, String> param) {
        return !this.isUpdate(param);
    }

    protected Date getDate(String str) {
        return this.getDate(str, null);
    }

    protected Date getDate(String str, Date defaultValue) {
        return MainUtils.getDate(str, defaultValue);
    }
}
